package com.springcloud.auth.modular.auth.controller;


import cn.hutool.core.net.NetUtil;
import com.springcloud.auth.config.OauthConfig;
import com.springcloud.auth.service.TTokenService;
import com.springcloud.auth.utils.OauthUtils;
import com.springcloud.auth.vo.TokenVo;
import com.springcloud.commom.api.R;
import com.springcloud.commom.utils.RedisUtil;
import com.springcloud.commom.utils.UUIDUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.oltu.oauth2.as.issuer.OAuthIssuer;
import org.apache.oltu.oauth2.as.request.OAuthAuthzRequest;
import org.apache.oltu.oauth2.as.request.OAuthTokenRequest;
import org.apache.oltu.oauth2.as.response.OAuthASResponse;
import org.apache.oltu.oauth2.client.OAuthClient;
import org.apache.oltu.oauth2.client.URLConnectionClient;
import org.apache.oltu.oauth2.client.request.OAuthClientRequest;
import org.apache.oltu.oauth2.client.response.OAuthAccessTokenResponse;
import org.apache.oltu.oauth2.common.OAuth;
import org.apache.oltu.oauth2.common.message.OAuthResponse;
import org.apache.oltu.oauth2.common.message.types.GrantType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 授权控制器
 *
 * @author hzl
 */

@RequestMapping("/oauth")
@Controller
public class OauthController {

    protected Logger logger = LoggerFactory.getLogger(this.getClass());


    @Resource
    private RedisUtil redis;

    @Resource
    private TTokenService tokenService;

    String clientId = "clientId";
    String clientSecret = "clientSecret";
    String response_type = "code";
    String redirectUrlPage = "redirectUrlPage";

    @Value("${server.port}")
    private String serverPort;

//	/**
//	 * 请求通过凭证地址
//	 */
//	String getAccessTokenURL = "http://localhost:8090/oauth/getAccessToken";
//	/**
//	 * 请求资源地址
//	 */
//	String userInfoUrl = "http://localhost:8090/oauth/getResource";

    /**
     * 重定向到请求 授权码的url
     *
     * @return
     * @throws Exception
     */
    @RequestMapping("/redirectToRequestAuthorizationCodeURL")
    public String redirectToRequestAuthorizationCodeURL(HttpServletRequest request) throws Exception {
        String url = "getAuthorizationCode";

        // 加入一个而随机码
        String randomCode = request.getParameter("randomCode");
        // accessTokenRequest 是用来描述请求对象的，描述了请求地址，和请求参数
        OAuthClientRequest accessTokenRequest = OAuthClientRequest.authorizationLocation(url)
                .setResponseType(response_type).setClientId(clientId).setRedirectURI(redirectUrlPage)
                .setParameter("randomCode", randomCode).buildQueryMessage();

        logger.info("accessTokenRequest.getLocationUri():{}", accessTokenRequest.getLocationUri());
        return "redirect:" + accessTokenRequest.getLocationUri();
    }

    /**
     * 返回授权码
     *
     * @param model
     * @param request
     * @return
     * @throws Exception
     */
    @RequestMapping("/getAuthorizationCode")
    public Object getAuthorizationCode(Model model, HttpServletRequest request) throws Exception {
        OAuthAuthzRequest oauthRequest = new OAuthAuthzRequest(request);

        logger.info("OAuth.OAUTH_REDIRECT_URI:{}", OAuth.OAUTH_REDIRECT_URI);
        logger.info("OAuth.OAUTH_RESPONSE_TYPE:{}", OAuth.OAUTH_RESPONSE_TYPE);

        String redirectURI = oauthRequest.getParam(OAuth.OAUTH_REDIRECT_URI);
        String clientId = oauthRequest.getClientId();
        String responseType = oauthRequest.getParam(OAuth.OAUTH_RESPONSE_TYPE);

        // 加入一个而随机码key
        String randomCode = request.getParameter("randomCode");
        // 得到数据以后应该检查数据

        logger.info("redirectURI:{}", redirectURI);
        logger.info("clientId:{}", clientId);
        logger.info("responseType:{}", responseType);

        // 把 state 写到一个 重定向的响应
        OAuthASResponse.OAuthAuthorizationResponseBuilder builder = OAuthASResponse.authorizationResponse(request,
                HttpServletResponse.SC_FOUND);

        // 生成一个随机码 value
        String code = UUIDUtils.createUUId();

        // 保存code
        redis.set(randomCode, code, OauthConfig.CODE_EXPIRE);

        builder.setCode(code);

        OAuthResponse response = builder.location(redirectURI).setParam("randomCode", randomCode).buildQueryMessage();

        logger.info("response.getLocationUri():{}", response.getLocationUri());
        return "redirect:" + response.getLocationUri();

    }

    /**
     * 请求通过凭证
     *
     * @param request
     * @return
     * @throws Exception
     */
    @RequestMapping("/redirectUrlPage")
    public HttpEntity<TokenVo> redirectUrlPage(HttpServletRequest request) throws Exception {
        String code = request.getParameter("code");
        String randomCode = request.getParameter("randomCode");

        String getAccessTokenURL = getBaseUrl() + OauthConfig.GET_ACCESS_TOKEN_URL;

        OAuthClient oAuthClient = new OAuthClient(new URLConnectionClient());

        logger.info("code:{}", code);
        logger.info("GrantType.AUTHORIZATION_CODE:{}", GrantType.AUTHORIZATION_CODE);

        OAuthClientRequest accessTokenRequest = OAuthClientRequest.tokenLocation(getAccessTokenURL)
                .setGrantType(GrantType.AUTHORIZATION_CODE).setClientId(clientId).setClientSecret(clientSecret)
                .setParameter("randomCode", randomCode).setCode(code).setRedirectURI(redirectUrlPage)
                .buildQueryMessage();

        OAuthAccessTokenResponse oAuthResponse = oAuthClient.accessToken(accessTokenRequest, OAuth.HttpMethod.POST);

        // 得到通过凭证和过期时间
        String accessToken = oAuthResponse.getAccessToken();
        String refreshToken = oAuthResponse.getRefreshToken();

        logger.info("accessToken:{}", accessToken);
        logger.info("refreshToken:{}", refreshToken);

        TokenVo token = new TokenVo();
        token.setAcToken(accessToken);
        token.setReToken(refreshToken);

        // 返回信息给前端
        return new ResponseEntity<TokenVo>(token, HttpStatus.OK);

    }

    /**
     * 返回通过凭证
     *
     * @param request
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "/getAccessToken", method = RequestMethod.POST)
    public HttpEntity<String> getAccessToken(HttpServletRequest request) throws Exception {

        logger.info("=============获取token开始=============");

        String randomCode = request.getParameter("randomCode");

        // 构建OAuth请求
        OAuthTokenRequest oauthRequest = new OAuthTokenRequest(request);

        String authCode = oauthRequest.getParam(OAuth.OAUTH_CODE);
        String clientSecret = oauthRequest.getClientSecret();

        logger.info("authCode:{}", authCode);
        logger.info("clientSecret:{}", clientSecret);

        // 验证code
        logger.info("========验证授权码======");
        String reCode = redis.get(randomCode);

        if (reCode.equals(authCode)) {
            logger.info("====授权码验证通过======");

            // 清除code
            redis.del(randomCode);
        }

        // 生成Access Token
        OAuthIssuer oauthIssuer = OauthUtils.createTokenInfo();

        String refreshToken = oauthIssuer.refreshToken();
        String accessToken = oauthIssuer.accessToken();
        logger.info("======code:{}", authCode);

        OAuthResponse response = OAuthASResponse.tokenResponse(HttpServletResponse.SC_OK).setAccessToken(accessToken)
                .setRefreshToken(refreshToken).buildJSONMessage();
        ResponseEntity<String> re = new ResponseEntity<String>(response.getBody(),
                HttpStatus.valueOf(response.getResponseStatus()));

        logger.info("re{}:", re.toString());
        logger.info("=============获取token结束=============");
        return re;
    }

    /**
     * 刷新accessToken
     *
     * @param
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "refreshAcToken", method = RequestMethod.POST)
    @ResponseBody
    public R<TokenVo> refreshAcToken(String refreshToken) throws Exception {
        R<TokenVo> resultBean = tokenService.refreshAccessToken(refreshToken);

        return resultBean;
    }

    /**
     * 检查acToken是否过期
     *
     * @return
     */
    @RequestMapping(value = "checkAcToken", method = RequestMethod.POST)
    @ResponseBody
    public R checkAcToken(String acToken) {
        Boolean isHas = false;

        String token = redis.get(OauthConfig.AUTH_ACCESS_TOKEN + acToken);
        if (!StringUtils.isBlank(token)) {
            isHas = true;
        }

        return R.data(isHas);
    }

    private String getBaseUrl() {
        String baseUrl = "http://" + NetUtil.getLocalhostStr() + ":" + serverPort;
        return baseUrl;
    }

}
